#ifndef _APPLICATION_H_
#define _APPLICATION_H_

#ifdef _WIN32
#pragma once
#endif

#include <Windows.h>
#include <string>

#include "d3dx9.h"
#include "fmod.hpp"
#include <boost/filesystem.hpp>

#include "devicemanager.h"
#include "input.h"
#include "keyboard.h"
#include "mouse.h"
#include "displayablecontainer.h"
#include "camera.h"
#include "constants.h"
#include "lightcontainer.h"
#include "map.h"
#include "light.h"
#include "mapcontainer.h"
#include "maploader.h"
#include "skybox.h"
#include "fontmanager.h"
#include "menucontainer.h"
#include "menu.h"
#include "ui.h"
#include "ui_sprite.h"
#include "ui_number.h"
#include "utils.h"
#include "mapmenu.h"
#include "menuvalue.h"
#include "value_option.h"
#include "soundmanager.h"
#include "sound.h"

#include "resource.h"

using std::string;

class CApplication
{
public:
    static CApplication *getInstance();

    bool initialise(HINSTANCE hInst);
    void gameLoop();
    LRESULT handleWindowMessage(HWND hWnd, UINT msg, WPARAM wParam, 
                                LPARAM lParam);

    void loadMap(string szMapName);

    void updateVolume(float fMasterVolume);
    void setMute(bool bMute);

    void startMusic();
    void stopMusic();

private:
    CApplication();
    ~CApplication();
    CApplication(const CApplication &rhs) {}
    CApplication &operator=(CApplication &other) {}

    void createWindow();
    void createInputDevices();
    
    void loadLights();
    void loadFonts();
    void loadSprites();
    void loadSounds();
    void loadMenus();

    void render() const;
    HRESULT setupDirectX();
    void tick();

    LPDIRECT3D9 m_pD3D;
    HINSTANCE m_hinstMainInstance;
    HWND m_hwndMainWindow;

    FMOD::Channel *m_pBombermanVocal;
    FMOD::Channel *m_pMenuAmbient;

};

namespace Application
{
    LRESULT CALLBACK handleWindowMessageProc(HWND hWnd, UINT msg, WPARAM wParam,
        LPARAM lParam);
    void keyboardCallback(const DEVICE_EVENT &evt);
    void mouseCallback(const DEVICE_EVENT &evt);

    void credits(CMenu *pMenu, COption *pOption, DELAY_PARAMS &params);
    //void selectMap(CMenu *pMenu, COption *pOption, DELAY_PARAMS &params);
};

namespace PauseCallbacks
{
    void continue_(CMenu *pMenu, COption *pOption, DELAY_PARAMS &params,
        unsigned char chKey);
    void restart(CMenu *pMenu, COption *pOption, DELAY_PARAMS &params,
        unsigned char chKey);
    void exit(CMenu *pMenu, COption *pOption, DELAY_PARAMS &params,
        unsigned char chKey);
}

namespace Options
{
    void volume(CMenu *pMenu, COption *pOption, DELAY_PARAMS &params,
        utils::PARAM &param, unsigned char chKey);
    void mute(CMenu *pMenu, COption *pOption, DELAY_PARAMS &params,
        utils::PARAM &param, unsigned char chKey);
    void back(CMenu *pMenu, COption *pOption, DELAY_PARAMS &params,
        utils::PARAM &param, unsigned char chKey);
}

namespace Back
{
    void back(CMenu *pMenu, COption *pOption, DELAY_PARAMS &params,
        unsigned char chKey);
}

#endif